# coding=utf-8
import os
import platform
import time
import uuid
# import tkinter
# from tkinter import *
from hk.hc_net_sdk import *
from datetime import datetime
import requests
import json
from flask import Flask,request,jsonify
from car_plate_info import car_plate_distinguish
import pymysql.cursors
from configparser import ConfigParser
# 系统环境标识
WINDOWS_FLAG = True
# 报警信息列表，报一次在回调中加1次记录
alarm_info = []
server = Flask(__name__)
# 读取配置文件
conf = ConfigParser()
conf.read("setting.ini",encoding='utf-8')
# 数据库连接
def mysql():
    mydb = pymysql.connect(
        host=conf.get("mysql_settings","host"),
        port=int(conf.get("mysql_settings","port")),
        user=conf.get("mysql_settings","user"),
        password=conf.get("mysql_settings","password"),
        database='device_info',
        cursorclass=pymysql.cursors.DictCursor
    )
    return mydb
# 获取当前系统环境
def GetPlatform():
    sysstr = platform.system()
    print('' + sysstr)
    if sysstr != "Windows":
        global WINDOWS_FLAG
        WINDOWS_FLAG = False

# 设置SDK初始化依赖库路径
def SetSDKInitCfg(sdk):
    # 设置HCNetSDKCom组件库和SSL库加载路径
    # print(os.getcwd())
    if WINDOWS_FLAG:
        strPath = os.getcwd().encode('gbk')
        sdk_ComPath = NET_DVR_LOCAL_SDK_PATH()
        sdk_ComPath.sPath = strPath
        sdk.NET_DVR_SetSDKInitCfg(2, byref(sdk_ComPath))
        sdk.NET_DVR_SetSDKInitCfg(3, create_string_buffer(strPath + b'\libcrypto-1_1-x64.dll'))
        sdk.NET_DVR_SetSDKInitCfg(4, create_string_buffer(strPath + b'\libssl-1_1-x64.dll'))
    else:
        strPath = os.getcwd().encode('utf-8')
        sdk_ComPath = NET_DVR_LOCAL_SDK_PATH()
        sdk_ComPath.sPath = strPath
        sdk.NET_DVR_SetSDKInitCfg(2, byref(sdk_ComPath))
        sdk.NET_DVR_SetSDKInitCfg(3, create_string_buffer(strPath + b'/libcrypto.so.1.1'))
        sdk.NET_DVR_SetSDKInitCfg(4, create_string_buffer(strPath + b'/libssl.so.1.1'))

# 报警信息回调函数实现代码
def g_fMessageCallBack_Alarm(lCommand, pAlarmer, pAlarmInfo, dwBufLen, pUser):
    """
    解析报警信息
    """
    global alarm_info
    Alarmer = pAlarmer.contents  # 取指针指向的结构体
    single_alrm = {}
    deviceSeriel = ''
    deviceIP = ''
    single_alrm['lCommand'] = hex(lCommand)

    if Alarmer.bySerialValid:
        for n in Alarmer.sSerialNumber[0:48]:
            if n != 0:
                deviceSeriel += chr(n)
        #single_alrm['设备序列号:'] = deviceSeriel
        single_alrm['number'] = deviceSeriel
    if Alarmer.byDeviceIPValid:
        for n in Alarmer.sDeviceIP[0:128]:
            if n != 0:
                deviceIP += chr(n)
        single_alrm['设备IP: '] = deviceIP

    if Alarmer.byUserIDValid:
        single_alrm['lUserID'] = Alarmer.lUserID

    # 移动侦测、视频丢失、遮挡、IO信号量等报警信息(V3.0以上版本支持的设备)
    if lCommand == 0x4000:
        print('移动侦测')
        Alarm_struct = cast(pAlarmInfo,
                            LPNET_DVR_ALARMINFO_V30).contents  # 当lCommand是COMM_ALARM时将pAlarmInfo强制转换为NET_DVR_ALARMINFO类型的指针再取值
        single_alrm['dwAlarmType'] = hex(Alarm_struct.dwAlarmType)
        single_alrm['byAlarmOutputNumber'] = Alarm_struct.byAlarmOutputNumber[0]
        single_alrm['byChannel'] = Alarm_struct.byChannel[0]

    if lCommand == 0x1102:
        print('行为分析事件上传')
        Alarm_struct = cast(pAlarmInfo, LPNET_VCA_RULE_ALARM).contents
        single_alrm['dwSize'] = Alarm_struct.dwSize
        single_alrm['dwRelativeTime'] = Alarm_struct.dwRelativeTime
        single_alrm['dwAbsTime'] = Alarm_struct.dwAbsTime
        single_alrm['wEventTypeEx'] = hex(Alarm_struct.struRuleInfo.wEventTypeEx)
        single_alrm['byChannel'] = Alarm_struct.struDevInfo.byChannel
        single_alrm['byIvmsChannel'] = Alarm_struct.struDevInfo.byIvmsChannel
        #single_alrm['struDevIP'] = bytearray(Alarm_struct.struDevInfo.struDevIP.sIpV4)
        sIpV4 = {'sIpV4':bytearray(Alarm_struct.struDevInfo.struDevIP.sIpV4).decode()}
        single_alrm['struDevIP'] = sIpV4['sIpV4'].strip(b'\x00'.decode())
        # 抓拍图片
        PicDataLen = Alarm_struct.dwPicDataLen
        name = datetime.now().strftime("%Y%m%d%H%M%S")
        if PicDataLen != 0:
            buff1 = string_at(Alarm_struct.pImage, PicDataLen)
            #with open('../../pic/'+name+'.jpg', 'wb') as fp:
            with open('/mnt/work/www/upload/'+name+'.jpg', 'wb') as fp:
                fp.write(buff1)
        single_alrm['pic'] = name+'.jpg'
    if lCommand == 0x3050:
        print('交通抓拍结果')
        Alarm_struct = cast(pAlarmInfo, LPNET_ITS_PLATE_RESULT).contents
        single_alrm['dwSize'] = Alarm_struct.dwSize
        sLicense = {'sLicense':bytearray(Alarm_struct.struPlateInfo.sLicense).decode('gb2312')}
        single_alrm['sLicense'] = sLicense['sLicense'].strip(b'\x00'.decode())
        alarm_info.append(single_alrm)
        jsons = alarm_info[-1]
        print(jsons)
        # 车牌识别查询、开闸
        car_plate_distinguish(jsons)
    alarm_info.append(single_alrm)
    return True

# 回调函数定义，需要是全局的
setdvrmsg_callback_func = MSGCallBack_V31(g_fMessageCallBack_Alarm)


# 道闸布防
def place_troops_on_garrison_duty():
    try:
        jsons = request.json
        if jsons.__contains__('ip') and jsons.__contains__('user_name') and jsons.__contains__('password'):
            # 设备ip
            ip = jsons['ip']
            # 设备用户名
            user_name = jsons['user_name']
            # 设备登录密码
            password = jsons['password']
            if ip is None or ip == '':return jsonify(code=1,msg="ip不能为空!")
            if user_name is None or user_name == '':return jsonify(code=1,msg="user_name不能为空!")
            if password is None or password == '':return jsonify(code=1,msg="password不能为空!")
            # 获取系统平台
            GetPlatform()

            # 加载库,先加载依赖库
            if WINDOWS_FLAG:
                #os.chdir(r'./lib/win')
                #os.chdir('D:\ideaworkspace\python_iot\python\gatewaybox\hk\lib\win')
                os.chdir('/mnt/work/python/gatewaybox/hk/lib/win')
                sdk = ctypes.CDLL(r'./HCNetSDK.dll')
            else:
                #os.chdir(r'./lib/linux')
                os.chdir('/mnt/work/python/gatewaybox/hk/lib/linux')
                sdk = cdll.LoadLibrary(r'./libhcnetsdk.so')
            SetSDKInitCfg(sdk)  # 设置组件库和SSL库加载路径

            # 初始化
            sdk.NET_DVR_Init()
            # 启用SDK写日志
            sdk.NET_DVR_SetLogToFile(3, bytes('../../log/SdkLog_Python/', encoding="utf-8"), False)

            # 通用参数配置
            sdkCfg = NET_DVR_LOCAL_GENERAL_CFG()
            sdkCfg.byAlarmJsonPictureSeparate = 1
            sdk.NET_DVR_SetSDKLocalCfg(17, byref(sdkCfg))

            # 设置报警回调函数
            sdk.NET_DVR_SetDVRMessageCallBack_V31(setdvrmsg_callback_func, None)
            # 初始化用户id, 在调用正常是程序一般返回正数，故初始化一个负数
            UserID = c_long(-1)

            # 用户注册设备
            # c++传递进去的是byte型数据，需要转成byte型传进去，否则会乱码
            # 登录参数，包括设备地址、登录用户、密码等
            struLoginInfo = NET_DVR_USER_LOGIN_INFO()
            struLoginInfo.bUseAsynLogin = 0  # 同步登录方式
            #struLoginInfo.sDeviceAddress = bytes("192.168.0.9", "ascii")  # 设备IP地址
            struLoginInfo.sDeviceAddress = bytes(ip, "ascii")  # 设备IP地址
            struLoginInfo.wPort = 8000  # 设备服务端口
            struLoginInfo.sUserName = bytes(user_name, "ascii")  # 设备登录用户名
            struLoginInfo.sPassword = bytes(password, "ascii")  # 设备登录密码
            struLoginInfo.byLoginMode = 0

            # 设备信息, 输出参数
            struDeviceInfoV40 = NET_DVR_DEVICEINFO_V40()

            UserID = sdk.NET_DVR_Login_V40(byref(struLoginInfo), byref(struDeviceInfoV40))
            if UserID < 0:
                print("Login failed, error code: %d" % sdk.NET_DVR_GetLastError())
                sdk.NET_DVR_Cleanup()
            else:
                print("UserID %s" % UserID)
                print(str(struDeviceInfoV40.struDeviceV30.sSerialNumber))
                print('登录成功，设备序列号：%s' % str(struDeviceInfoV40.struDeviceV30.sSerialNumber, encoding = "utf8"))
                # 布防句柄
                handle = c_long(-1)
                sdk.NET_DVR_SetupAlarmChan_V41.restype = c_long

                # 启用布防
                struAlarmParam = NET_DVR_SETUPALARM_PARAM()
                struAlarmParam.dwSize = sizeof(struAlarmParam)
                struAlarmParam.byAlarmInfoType = 1  # 智能交通报警信息上传类型：0- 老报警信息（NET_DVR_PLATE_RESULT），1- 新报警信息(NET_ITS_PLATE_RESULT)
                struAlarmParam.byDeployType = 1 # 布防类型：0-客户端布防，1-实时布防
                handle = sdk.NET_DVR_SetupAlarmChan_V41(UserID, byref(struAlarmParam))
                if handle < 0:
                    print("NET_DVR_SetupAlarmChan_V41 失败, error code: %d" % sdk.NET_DVR_GetLastError())
                    sdk.NET_DVR_Logout(UserID)
                    sdk.NET_DVR_Cleanup()
                else:
                    number = str(struDeviceInfoV40.struDeviceV30.sSerialNumber, encoding = "utf8")
                    number = number[:35]
                    # 更新设备的句柄、用户id
                    mydb = mysql()
                    mydb.connect()
                    cursor = mydb.cursor()
                    sql = "UPDATE device_info SET handle ='"+str(handle)+"',user_id ='"+str(UserID)+"' WHERE number = '" + number + "'"
                    insert = cursor.execute(sql)
                    mydb.commit()
                    cursor.close()  # 关闭游标
                    mydb.close() # 关闭连接
                    print("handle %s" % handle)
        else:
            return jsonify(code=1,msg="缺少必要参数ip、user_name、password")
    except Exception as e:
        print(e)
        return jsonify(
            code=1,
            msg="Server internal error"
        )
    return jsonify(
        code=0,
        msg="success"
    )

# 撤防
def withdraw_garrison():

    try:
        jsons = request.json
        if jsons.__contains__('handle') and jsons.__contains__('user_id'):
            # 海康布防手柄
            handle = jsons['handle']
            # 海康登录ID
            user_id = jsons['user_id']
            if handle is None or handle == '':return jsonify(code=1,msg="请先布防再撤防,谢谢!")
            if user_id is None or user_id == '':return jsonify(code=1,msg="请先布防再撤防,谢谢!")
            # 获取系统平台
            GetPlatform()

            # 加载库,先加载依赖库
            if WINDOWS_FLAG:
                #os.chdir(r'./lib/win')
                #os.chdir('D:\ideaworkspace\python_iot\python\gatewaybox\hk\lib\win')
                os.chdir('/mnt/work/python/gatewaybox/hk/lib/win')
                sdk = ctypes.CDLL(r'./HCNetSDK.dll')
            else:
                #os.chdir(r'./lib/linux')
                os.chdir('/mnt/work/python/gatewaybox/hk/lib/linux')
                sdk = cdll.LoadLibrary(r'./libhcnetsdk.so')
            SetSDKInitCfg(sdk)  # 设置组件库和SSL库加载路径
            # # 撤销布防，退出程序时调用
            sdk.NET_DVR_CloseAlarmChan_V30(handle)
            # # 注销用户，退出程序时调用
            sdk.NET_DVR_Logout(user_id)
            # # 释放SDK资源，退出程序时调用
            sdk.NET_DVR_Cleanup()
        else:
            return jsonify(code=1,msg="缺少必要参数handle、user_id")
    except Exception as e:
        print(e)
        return jsonify(
            code=1,
            msg="Server internal error"
        )
    return jsonify(
        code=0,
        msg="success"
    )




